import logging
from logging.handlers import RotatingFileHandler
from pathlib import Path
from typing import Dict, Any, Optional

class LoggerManager:
    """Centralized logging management for the distributed system.
    
    This class provides unified logging configuration and management,
    supporting both file and console output with customizable formats.
    """
    
    def __init__(self, config: Dict[str, Any]):
        """Initialize the logger manager.
        
        Args:
            config: Logging configuration parameters
        """
        self.config = config
        self.log_dir = Path(config.get('log_dir', 'logs'))
        self.log_dir.mkdir(parents=True, exist_ok=True)
        
        # Default logging format
        self.log_format = config.get(
            'format',
            '%(asctime)s - %(name)s - %(levelname)s - %(message)s'
        )
        
        # Configure root logger
        self._setup_root_logger()
    
    def _setup_root_logger(self) -> None:
        """Configure the root logger with basic settings."""
        root_logger = logging.getLogger()
        root_logger.setLevel(self._get_log_level())
        
        # Remove existing handlers
        for handler in root_logger.handlers[:]:  
            root_logger.removeHandler(handler)
        
        # Add console handler
        if self.config.get('console_output', True):
            console_handler = logging.StreamHandler()
            console_handler.setFormatter(logging.Formatter(self.log_format))
            root_logger.addHandler(console_handler)
    
    def _get_log_level(self) -> int:
        """Get logging level from configuration.
        
        Returns:
            int: Logging level
        """
        level = self.config.get('level', 'INFO').upper()
        return getattr(logging, level, logging.INFO)
    
    def get_logger(self, name: str,
                   file_output: bool = True,
                   max_bytes: int = 10485760,  # 10MB
                   backup_count: int = 5) -> logging.Logger:
        """Get a configured logger instance.
        
        Args:
            name: Logger name
            file_output: Whether to enable file output
            max_bytes: Maximum size of log file before rotation
            backup_count: Number of backup files to keep
            
        Returns:
            logging.Logger: Configured logger instance
        """
        logger = logging.getLogger(name)
        
        # Add file handler if requested
        if file_output:
            log_file = self.log_dir / f"{name}.log"
            file_handler = RotatingFileHandler(
                filename=str(log_file),
                maxBytes=max_bytes,
                backupCount=backup_count
            )
            file_handler.setFormatter(logging.Formatter(self.log_format))
            logger.addHandler(file_handler)
        
        return logger
    
    def update_log_level(self, level: str) -> None:
        """Update the logging level for all handlers.
        
        Args:
            level: New logging level
        """
        numeric_level = getattr(logging, level.upper(), None)
        if not isinstance(numeric_level, int):
            raise ValueError(f"Invalid log level: {level}")
            
        root_logger = logging.getLogger()
        root_logger.setLevel(numeric_level)
        
        # Update all handlers
        for handler in root_logger.handlers:
            handler.setLevel(numeric_level)
    
    def add_file_handler(self, logger_name: str,
                         file_name: Optional[str] = None,
                         max_bytes: int = 10485760,
                         backup_count: int = 5) -> None:
        """Add a file handler to an existing logger.
        
        Args:
            logger_name: Name of the logger
            file_name: Custom log file name (default: logger_name.log)
            max_bytes: Maximum size of log file before rotation
            backup_count: Number of backup files to keep
        """
        logger = logging.getLogger(logger_name)
        
        if file_name is None:
            file_name = f"{logger_name}.log"
        
        log_file = self.log_dir / file_name
        handler = RotatingFileHandler(
            filename=str(log_file),
            maxBytes=max_bytes,
            backupCount=backup_count
        )
        handler.setFormatter(logging.Formatter(self.log_format))
        logger.addHandler(handler)